/**
 * 
 */
package com.excalibur.core.util.captcha;

import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Properties;

import javax.imageio.ImageIO;

import com.excalibur.core.util.PropertiesUtil;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;

/**
 * @author "Jiance Qin"
 * 
 * @date 2014年1月16日
 * 
 * @time 下午6:29:34
 * 
 */
public class CaptchaGenerator {

	public static final String DEFAULT_IMAGE_MIME_TYPE = "image/png";
	public static final String DEFAULT_IMAGE_TYPE = "png";

	private static ThreadLocal<DefaultKaptcha> captchaProducerThreadLocal = new ThreadLocal<DefaultKaptcha>();
	private static PropertiesUtil propertiesUtil = PropertiesUtil.newInstance("/captcha.properties");

	/**
	 * 
	 */
	private CaptchaGenerator() {

	}

	/**
	 * @return the captchaProducer
	 */
	public static DefaultKaptcha getCaptchaProducer() {

		DefaultKaptcha captchaProducer = captchaProducerThreadLocal.get();

		if (captchaProducer == null) {
			captchaProducer = new DefaultKaptcha();

			// Set image parameters
			Properties captchaProp = new Properties();
			captchaProp.put("kaptcha.border", propertiesUtil.getValue("kaptcha.border", "yes"));
			captchaProp.put("kaptcha.border.color", propertiesUtil.getValue("kaptcha.border.color", "black"));
			captchaProp.put("kaptcha.border.thickness", propertiesUtil.getValue("kaptcha.border.thickness", "1"));

			captchaProp.put("kaptcha.image.width", propertiesUtil.getValue("kaptcha.image.width", "100"));
			captchaProp.put("kaptcha.image.height", propertiesUtil.getValue("kaptcha.image.height", "40"));

			captchaProp.put("kaptcha.textproducer.font.names",
					propertiesUtil.getValue("kaptcha.textproducer.font.names", "Arial, Courier"));
			captchaProp.put("kaptcha.textproducer.font.color",
					propertiesUtil.getValue("kaptcha.textproducer.font.color", "black"));
			captchaProp.put("kaptcha.textproducer.font.size",
					propertiesUtil.getValue("kaptcha.textproducer.font.size", "22"));
			captchaProp.put("kaptcha.textproducer.char.string", propertiesUtil.getValue(
					"kaptcha.textproducer.char.string",
					"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"));
			captchaProp.put("kaptcha.textproducer.char.length",
					propertiesUtil.getValue("kaptcha.textproducer.char.length", "5"));
			captchaProp.put("kaptcha.textproducer.char.space",
					propertiesUtil.getValue("kaptcha.textproducer.char.space", "2"));
			captchaProp.put("kaptcha.textproducer.impl", propertiesUtil.getValue("kaptcha.textproducer.impl",
					"com.google.code.kaptcha.text.impl.DefaultTextCreator"));

			captchaProp.put("kaptcha.noise.color", propertiesUtil.getValue("kaptcha.noise.color", "255,0,0"));
			captchaProp.put("kaptcha.noise.impl",
					propertiesUtil.getValue("kaptcha.noise.impl", "com.google.code.kaptcha.impl.NoNoise"));

			captchaProp.put("kaptcha.background.impl", propertiesUtil.getValue("kaptcha.background.impl",
					"com.google.code.kaptcha.impl.DefaultBackground"));
			captchaProp.put("kaptcha.background.clear.from",
					propertiesUtil.getValue("kaptcha.background.clear.from", "127,127,127"));
			captchaProp.put("kaptcha.background.clear.to",
					propertiesUtil.getValue("kaptcha.background.clear.to", "255,255,255"));

			captchaProp.put("kaptcha.obscurificator.impl",
					propertiesUtil.getValue("kaptcha.obscurificator.impl", "com.google.code.kaptcha.impl.ShadowGimpy"));

			captchaProp.put("kaptcha.word.impl",
					propertiesUtil.getValue("kaptcha.word.impl", "com.excalibur.core.util.captcha.ThinWordRenderer"));

			// Set captcha configure
			captchaProducer.setConfig(new Config(captchaProp));
			captchaProducerThreadLocal.set(captchaProducer);
		}
		return captchaProducer;
	}

	/**
	 * @param captchaProducer
	 *            the captchaProducer to set
	 */
	public static void setCaptchaProducer(DefaultKaptcha captchaProducer) {

		captchaProducerThreadLocal.set(captchaProducer);
	}

	/**
	 * Generate a captcha text.
	 * 
	 * @return a string of captcha text
	 */
	public static String generateCaptchaText() {

		return getCaptchaProducer().createText();
	}

	/**
	 * Generate a captcha image using com.google.code.kaptcha.kaptcha lib.
	 * 
	 * @param captchaText
	 *            captcha text string used to generate image
	 * @return a byte array containing the image data
	 */
	public static byte[] generateCaptchaImage(String captchaText) {

		if (captchaText != null && !captchaText.isEmpty()) {

			// Generate captcha image
			BufferedImage captchaImage = getCaptchaProducer().createImage(captchaText);

			ByteArrayOutputStream os = new ByteArrayOutputStream();

			try {
				ImageIO.write(captchaImage, DEFAULT_IMAGE_TYPE, os);
			} catch (IOException e) {
				e.printStackTrace();
			}

			return os.toByteArray();
		} else {
			return null;
		}
	}

	/**
	 * Generate a captcha image using com.google.code.kaptcha.kaptcha lib.
	 * 
	 * @param captchaText
	 *            captcha text string used to generate image
	 * @param width
	 *            100
	 * @param height
	 *            40
	 * @param fontSize
	 *            22
	 * @param fontColor
	 *            black
	 * @param charLength
	 *            5
	 * @param charSpace
	 *            2
	 * @param hasBorder
	 *            true
	 * @param borderColor
	 *            black
	 * @param backgroundFrom
	 *            127,127,127
	 * @param backgroundTo
	 *            255,255,255
	 * @return a byte array containing the image data
	 */
	public static byte[] generateCaptchaImage(String captchaText, String width, String height, String fontSize,
			String fontColor, String charLength, String charSpace, boolean hasBorder, String borderColor,
			String backgroundFrom, String backgroundTo) {

		if (captchaText != null && !captchaText.isEmpty()) {

			// set width and height
			DefaultKaptcha producer = getCaptchaProducer();
			producer.getConfig().getProperties().put("kaptcha.image.width", width);
			producer.getConfig().getProperties().put("kaptcha.image.height", height);
			producer.getConfig().getProperties().put("kaptcha.textproducer.font.size", fontSize);
			producer.getConfig().getProperties().put("kaptcha.textproducer.char.length", charLength);
			producer.getConfig().getProperties().put("kaptcha.textproducer.char.space", charSpace);
			producer.getConfig().getProperties().put("kaptcha.textproducer.font.color", fontColor);
			producer.getConfig().getProperties().put("kaptcha.border", hasBorder ? "yes" : "no");
			producer.getConfig().getProperties().put("kaptcha.border.color", borderColor);
			producer.getConfig().getProperties().put("kaptcha.background.clear.from", backgroundFrom);
			producer.getConfig().getProperties().put("kaptcha.background.clear.to", backgroundTo);

			// Generate captcha image
			BufferedImage captchaImage = producer.createImage(captchaText);

			ByteArrayOutputStream os = new ByteArrayOutputStream();

			try {
				ImageIO.write(captchaImage, DEFAULT_IMAGE_TYPE, os);
			} catch (IOException e) {
				e.printStackTrace();
			}

			return os.toByteArray();
		} else {
			return null;
		}
	}
}
